
package HibernateLayer;

import POJOs.SCRUDBasic;
import POJOs.SCRUDidOnly;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
 *
 * @author fabiofurlan
 */
public abstract class VCRUDSingleSessionBasicServices <STRUCT extends SCRUDidOnly> {

    //TO DO UNIFY SESSION OPEN AND SESSION CLOSE

    SessionFactory sessionFactory;
    Class<STRUCT> type=getTypeClass();

    //This is a basic hibernate session constuctor.
    //if argument's value is null this method use the default settings.

    public VCRUDSingleSessionBasicServices(String mappingsPackagePath){

        Configuration cfg;

        if(mappingsPackagePath!=null){
            System.out.println("VCRUDBasicServices | Construct method | Using customized Hibernate Mapping");
            cfg = new Configuration().configure(mappingsPackagePath);
        }
        else{
            System.out.println("VCRUDBasicServices | Construct method | Using default Hibernate Mapping");
            cfg = new Configuration().configure("/HibernateMappings/hibernate.cfg.xml");
        }

        sessionFactory = cfg.buildSessionFactory();

    }


     public VCRUDSingleSessionBasicServices(){

         Configuration cfg;

         System.out.println("VCRUDBasicServices | Construct method | Using default Hibernate Mapping");
         cfg = new Configuration().configure("/HibernateMappings/hibernate.cfg.xml");

         sessionFactory = cfg.buildSessionFactory();

     }


    public boolean createBasicStructure(STRUCT s){
        try{
            Session session=sessionFactory.openSession();
            Transaction trx=session.beginTransaction();
            System.out.println("VCRUDBasicServices | createBasicStructure | Session-Transaction init.......DONE");

            try{
                session.save(s);
                trx.commit();
                session.close();
                return true;
            }
            catch(HibernateException ex){
                ex.printStackTrace();
                trx.rollback();
                session.close();
                return false;
            }
        }
        catch(Exception ex){
            ex.printStackTrace();
            return false;
        }
    }


    public List<STRUCT> list(){
        try {
            //Queste due righe vanno fattorizzate in un metodo apposito.
            Session session=sessionFactory.openSession();
            Transaction trx=session.beginTransaction();
            System.out.println("VCRUDBasicServices | list | Session-Transaction init.......DONE");

            try{
                List cdList=session.createQuery("from "+this.type.getName()+" c").list();
                trx.commit();
                session.close();
                return cdList;
            }

            catch(HibernateException ex){
                ex.printStackTrace();
                trx.rollback();
                session.close();
                return null;
            }

        } catch (Exception e) {
             e.printStackTrace();
            return null;
        }
    }

    //From an id return the requested object.
    public STRUCT simpleIDFinder(int id){

        try {
            Session session = sessionFactory.openSession();
            Transaction trx=session.beginTransaction();
            System.out.println("VCRUDBasicServices | simpleIDFinder | Session-Transaction init.......DONE");

            try{
                STRUCT returnValue=(STRUCT)session.get(type, id);
                trx.commit();
                session.close();
                return  returnValue;
            }
            catch(HibernateException ex){
                ex.printStackTrace();
                trx.rollback();
                session.close();
                return null;
            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public Boolean update(int id, STRUCT toUpdate){

        try {
            Session session = sessionFactory.openSession();
            Transaction trx=session.beginTransaction();
            System.out.println("VCRUDBasicServices | update | Session-Transaction init.......DONE");

            try{
                STRUCT valToUpdate=(STRUCT)session.get(type, id);
                valToUpdate=toUpdate;
                trx.commit();
                session.close();
                return new Boolean(true);
            }
            catch(HibernateException ex){
                ex.printStackTrace();
                trx.rollback();
                session.close();
                return new Boolean(false);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return new Boolean(false);
        }
    }

    public Boolean delete(int id){

        try {
            Session session = sessionFactory.openSession();
            Transaction trx=session.beginTransaction();
            System.out.println("VCRUDBasicServices | delete | Session-Transaction init.......DONE");

            try{
                STRUCT valToDelete=(STRUCT)session.get(type, id);
                session.delete(valToDelete);
                trx.commit();
                session.close();
                return new Boolean(true);
            }
            catch(HibernateException ex){
                ex.printStackTrace();
                trx.rollback();
                session.close();
                return new Boolean(false);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return new Boolean(false);
        }

    }


    //http://nileshk.com/node/66 there is an example of
    //general parameter reflaction, but this example doesn't work propertly
    //TODO: using reflaction.
    protected abstract Class<STRUCT> getTypeClass();


}
